package org.jaronsource.framework.plugins.security;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Collection;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jaronsource.framework.plugins.security.dao.ISecurityDao;
import org.jaronsource.framework.plugins.security.domain.IPerm;
import org.jaronsource.framework.plugins.security.domain.ISecurityUser;
import org.jaronsource.framework.plugins.security.domain.SecurityToken;
import org.jaronsource.framework.util.Base64;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class SecurityTokenHolder {

	public static final String SECURITY_TOKEN_KEY = "SECURITY_TOKEN_KEY";
	public static final String SECURITY_TOKEN = "SECURITY_TOKEN";

	private static Log logger = LogFactory.getLog( SecurityTokenHolder.class );

	public static SecurityToken getSecurityToken() {

		HttpServletRequest request = ( (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes() ).getRequest();
		return getSecurityToken( request );
	}

	public static SecurityToken getSecurityToken( HttpServletRequest request ) {

		HttpSession session = request.getSession();

		SecurityToken token = (SecurityToken) session.getAttribute( SECURITY_TOKEN_KEY );
		if ( token == null ) {

			Cookie[] cookies = request.getCookies() == null ? new Cookie[] {} : request.getCookies();

			for ( Cookie cookie : cookies ) {
				if ( SECURITY_TOKEN.equals( cookie.getName() ) ) {

					token = new SecurityToken();

					String cookieValue = cookie.getValue();
					ISecurityUser user = null;
					try {
						ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream( Base64.base64ToByteArray( cookieValue ) ) );
						user = (ISecurityUser) ois.readObject();
					}
					catch ( Exception e ) {
						if ( logger.isDebugEnabled() ) {
							logger.debug( "User info not found in cookie", e );
						}
					}

					ServletContext sc = session.getServletContext();
					WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext( sc );
					ISecurityDao securityDao = wac.getBean( ISecurityDao.class );
					Collection<IPerm> perms = securityDao.loadPerms( user );

					token.setUser( user );
					token.setPerms( perms );

					break;
				}
			}

			session.setAttribute( SECURITY_TOKEN_KEY, token );
		}

		return token;
	}

	public static void cleanSecurityToken( HttpServletResponse response ) {
		HttpServletRequest request = ( (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes() ).getRequest();
		request.getSession().setAttribute( SECURITY_TOKEN_KEY, null );

		Cookie[] cookies = request.getCookies() == null ? new Cookie[] {} : request.getCookies();

		for ( Cookie cookie : cookies ) {
			if ( SECURITY_TOKEN.equals( cookie.getName() ) ) {
				cookie.setMaxAge( 0 );
				response.addCookie( cookie );
				break;
			}
		}

	}

	public static void setSecurityToken(	HttpServletResponse response,
											SecurityToken token,
											boolean rememberme ) {
		HttpServletRequest request = ( (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes() ).getRequest();
		request.getSession().setAttribute( SECURITY_TOKEN_KEY, token );

		if ( rememberme ) {
			ISecurityUser user = token.getUser();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			try {
				ObjectOutputStream oos = new ObjectOutputStream( baos );
				oos.writeObject( user );
			}
			catch ( IOException e ) {
				if ( logger.isDebugEnabled() ) {
					logger.debug( "could not write user info to cookie", e );
				}
			}
			String jsonUser = Base64.byteArrayToBase64( baos.toByteArray() );
			Cookie cookie = new Cookie( SECURITY_TOKEN, jsonUser );
			cookie.setMaxAge( 60 * 60 * 24 * 365 );
			//cookie.setPath( "/" );
			response.addCookie( cookie );
		}
	}

	public static ISecurityUser getUser() {
		return getSecurityToken().getUser();
	}

	public static Collection<IPerm> getPerms() {
		return getSecurityToken().getPerms();
	}
}
